﻿using MKGlowSystem;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;

public class OptimiseAll
{
    private static int shadowCnt;
    private static int shaderCnt;
    private static int emptyAnimCnt;
    private static int nullAnim;
    private static int staticCnt;
    private static int lightCnt;
    private static int glowCnt;
    private static int ocCnt;

    private const string TYPE_MAP_PATH = "/Resources/Prefab/Map";

    [MenuItem("GameEditor/开启柔光和雾效", false, 30)]
    public static void OpenFogAndGlow()
    {
        ChangeFogAndGlow(true);
    }

    [MenuItem("GameEditor/关闭柔光和雾效", false, 30)]
    public static void CloseFogAndGlow()
    {
        ChangeFogAndGlow(false);
    }

    [MenuItem("GameEditor/一键打开阴影", false, 30)]
    public static void OpenShadow()
    {
        ChangeCastShadow(true);
    }

    [MenuItem("GameEditor/一键关闭阴影", false, 30)]
    public static void CloseShadow()
    {
        ChangeCastShadow(false);
    }

    [MenuItem("GameEditor/一键优化", false, 30)]
    public static void OneKeyOptimise()
    {
        Optimise();
    }

    static void ChangeFogAndGlow(bool open)
    {
        foreach (EditorBuildSettingsScene S in EditorBuildSettings.scenes)
        {
            if (S.enabled)
            {
                //得到关卡的名称
                string name = S.path;
                //打开这个关卡
                EditorSceneManager.OpenScene(name);
                RenderSettings.fog = open;

                foreach (GameObject obj in Object.FindObjectsOfType(typeof(GameObject)))
                {
                    MKGlow glow = obj.GetComponent<MKGlowSystem.MKGlow>();
                    if (glow != null)
                    {
                        glow.enabled = open;
                    }
                }
                EditorApplication.SaveScene();
            }
        }
    }
    
    public static void Optimise()
    {
        Clear(); int sceneIdx = 0; int sceneCnt = 0;
        foreach (EditorBuildSettingsScene S in EditorBuildSettings.scenes)
        {
            if (S.enabled) { ++sceneCnt; }
        }

        foreach (EditorBuildSettingsScene S in EditorBuildSettings.scenes)
        {
            if (S.enabled)
            {
                //得到关卡的名称
                string name = S.path; ++sceneIdx;
                EditorUtility.DisplayProgressBar("玩命优化中", string.Format("正在优化场景：{0}  ({1}/{2})",
                    S.path.Replace(@"Assets/Scenes/", ""), sceneIdx, sceneCnt), (float)sceneIdx / sceneCnt);

                //打开这个关卡
                EditorSceneManager.OpenScene(name);
                foreach (GameObject obj in Object.FindObjectsOfType(typeof(GameObject)))
                {
                    OptimizeObj(obj, S.path);
                }
                EditorApplication.SaveScene();
            }
        }

        string mapPath = Application.dataPath + TYPE_MAP_PATH;
        string[] dirs = System.IO.Directory.GetFiles(mapPath, "*.prefab", System.IO.SearchOption.TopDirectoryOnly);
        for (int i = 0; i < dirs.Length; i++)
        {
            string goPath = dirs[i].Replace(Application.dataPath, "Assets");
            string goRootPath = goPath.Replace(TYPE_MAP_PATH, "");
            GameObject targetGO = AssetDatabase.LoadAssetAtPath<GameObject>(goPath);
            EditorUtility.DisplayProgressBar("玩命优化中", string.Format("正在优化预设：{0} ({1}/{2})",
                goRootPath, i + 1, dirs.Length), (i + 1f) / dirs.Length);

            GameObject go = PrefabUtility.InstantiatePrefab(targetGO) as GameObject;
            OptimizeObj(go); PrefabUtility.ReplacePrefab(go, targetGO);
            Object.DestroyImmediate(go);
        }
        EditorUtility.ClearProgressBar();
        Debug.Log(string.Format("一键优化执行成功! 去掉实时阴影({0})处，修改({1})处Shader为Mobile类型，" +
            "删除({2})处静态物体动画，删除({3})处空动画, 启用静态({4})处, 禁用光源({5})处, 调整柔光{6}处, 关闭 OC {7}处",
            shadowCnt, shaderCnt, emptyAnimCnt, nullAnim, staticCnt, lightCnt, glowCnt, ocCnt));
    }

    static void OptimizeObj(GameObject obj, string scenePath = "")
    {
        DisableShadow(obj);
        ChangeToMobileDiffuse(obj);
        ClearStaticAnim(obj);
        CleanNullAnimChip(obj);
        DisableOC(obj);

        if (!scenePath.Contains("Exhibition"))
        {
            OffLight(obj);
        }
        if (obj.name == "Main_Camera")
        {
            AdjustGlow(obj);
        }
    }

    static void DisableOC(GameObject go)
    {
        Camera[] cams = go.GetComponentsInChildren<Camera>();
        for (int idx = 0; idx < cams.Length; ++idx)
        {
            Camera cam = cams[idx];
            if (cam.useOcclusionCulling)
            {
                cam.useOcclusionCulling = false;
                ++ocCnt;
            }
        }
    }

    static void DisableShadow(GameObject go)
    {
        MeshRenderer[] mrs = go.GetComponentsInChildren<MeshRenderer>();
        SkinnedMeshRenderer[] smrs = go.GetComponentsInChildren<SkinnedMeshRenderer>();
        for (int idx = 0; idx < mrs.Length; ++idx)
        {
            MeshRenderer mr = mrs[idx];
            if (mr != null)
            {
                if (mr.enabled && (mr.castShadows || mr.receiveShadows))
                {
                    mr.castShadows = false;
                    mr.receiveShadows = false;
                    ++shadowCnt;
                }
            }
        }

        for (int idx = 0; idx < smrs.Length; ++idx)
        {
            SkinnedMeshRenderer smr = smrs[idx];
            if (smr != null)
            {
                if (smr.enabled && (smr.castShadows || smr.receiveShadows))
                {
                    smr.castShadows = false;
                    smr.receiveShadows = false;
                    ++shadowCnt;
                }
            }
        }
    }

    static void ChangeToMobileDiffuse(GameObject go)
    {
        var rds = go.GetComponentsInChildren<Renderer>();
        for (int idx = 0; idx < rds.Length; ++idx)
        {
            Renderer rd = rds[idx];
            if (rd != null && rd.sharedMaterial != null && rd.sharedMaterial.shader.name 
                == "Diffuse" && rd.sharedMaterial.color == Color.white)
            {
                rd.sharedMaterial.shader = Shader.Find("Mobile/Diffuse");
                ++shaderCnt;
            }
        }
    }

    static void ClearStaticAnim(GameObject go)
    {
        Animator[] anims = go.GetComponentsInChildren<Animator>();
        for (int idx = 0; idx < anims.Length; ++idx)
        {
            Animator anim = anims[idx];
            if (anim != null && anim.gameObject.isStatic)
            {
                Object.DestroyImmediate(anim);
                ++emptyAnimCnt;
            }
        }
    }

    static void CleanNullAnimChip(GameObject go)
    {
        Animator[] ams = go.GetComponentsInChildren<Animator>();
        for (int idx = 0; idx < ams.Length; ++idx)
        {
            Animator am = ams[idx];
            if (am != null)
            {
                if (am.runtimeAnimatorController == null)
                {
                    Object.DestroyImmediate(am);
                    ++nullAnim;
                }
            }
        }
    }

    static void EnableStatic(GameObject go)
    {
        Animator[] ams = go.GetComponentsInChildren<Animator>();
        for (int idx = 0; idx < ams.Length; ++idx)
        {
            Animator am = ams[idx];
            if ((am != null && am.runtimeAnimatorController != null) 
                || go.GetComponentInChildren<UITweener>() != null)
            {
                continue;
            }
            if (go.GetComponent<Rigidbody>() != null)
            {
                continue;
            }
            if (!go.isStatic)
            {
                go.isStatic = true;
                ++staticCnt;
            }
        }
    }

    static void AdjustGlow(GameObject go)
    {
        MKGlow[] glows = go.GetComponentsInChildren<MKGlow>();
        for (int idx = 0; idx < glows.Length; ++idx)
        {
            MKGlow glow = glows[idx];
            glow.GlowQuality = MKGlowQuality.Low;
            glow.BlurIterations = Mathf.Min(2, glow.BlurIterations);
            ++glowCnt;
        }
    }

    static void OffLight(GameObject go)
    {
        Light[] lights = go.GetComponentsInChildren<Light>();
        for (int idx = 0; idx < lights.Length; ++idx)
        {
            Light l = lights[idx];
            l.gameObject.SetActive(false);
            ++lightCnt;
        }
    }
    
    static void ChangeCastShadow(bool open)
    {
        foreach (GameObject obj in Object.FindObjectsOfType(typeof(GameObject)))
        {
            if (obj.GetComponent<Renderer>() != null)
            {
                obj.GetComponent<Renderer>().castShadows = open;
                obj.GetComponent<Renderer>().receiveShadows = open;
            }
        }
        EditorApplication.SaveScene();
    }

    static void Clear()
    {
        shadowCnt = 0;
        shaderCnt = 0;
        emptyAnimCnt = 0;
        nullAnim = 0;
        staticCnt = 0;
        lightCnt = 0;
        glowCnt = 0;
        ocCnt = 0;
    }
}